
#include <BPainter>
#include <BStyle>
#include <BImage>
#include <BFont>
#include <BEvent>
#include <BChangeEvent>
#include <BMouseEvent>
#include <BStyle>

#include <BButton>
#include "member_BButton.h"

using namespace BWE;

#define member					(*(member_BButton*)_ptr)
#define member_allocate()		_ptr = new member_BButton(this)
#define member_release()		delete (member_BButton*)_ptr

BButton::BButton(BWidget* parent) : BWidget(parent)
{
	member_allocate();
}
BButton::BButton(const BString& text, BWidget* parent) : BWidget(parent)
{
	member_allocate();
	setText(text);
}
BButton::BButton(BImage* image, BWidget* parent) : BWidget(parent)
{
	member_allocate();
	setImage(image);
}
BButton::BButton(BImage* image, const BString& text, BWidget* parent) : BWidget(parent)
{
	member_allocate();
	setImage(image);
	setText(text);
}
BButton::~BButton()
{
	member_release();
}

void BButton::setAlign(Align align)
{
	if (member.align != align)
	{
		member.align = align;
		member.dirty = true;
		this->fresh();
	}
}
Align BButton::align() const
{
	return member.align;
}

void BButton::setText(const BString& text)
{
	if(member.text != text)
	{
		member.text = text;
		member.dirty = true;
		this->fresh();
	}
}
const BString& BButton::text() const
{
	return member.text;
}

void BButton::setColor(const BColor& color)
{
	if (member.color != color)
	{
		member.color = color;
		this->fresh();
	}
}
const BColor& BButton::color() const
{
	return member.color;
}

void BButton::setImage(BImage* image)
{
	if(member.image != image)
	{
		member.image = image;
		emit(Signal_ImageChanged, member.image.ptr());
		member.dirty = true;
		this->fresh();
	}
}
BImage* BButton::image()
{
	return member.image.ptr();
}
const BImage* BButton::image() const
{
	return member.image.ptr();
}

void BButton::setIcon(BIcon* icon)
{
	if (member.icon != icon)
	{
		member.icon = icon;
		member.dirty = true;
		this->adjust();
		this->fresh();
	}
}
const BIcon* BButton::icon() const
{
	return member.icon;
}
BIcon* BButton::icon()
{
	return member.icon;
}

void BButton::setIconAlone(bool iconAlone)
{
	if (member.iconAlone != iconAlone)
	{
		member.iconAlone = iconAlone;
		this->fresh();
	}
}
bool BButton::iconAlone() const
{
	return member.iconAlone;
}

void BButton::setIconSize(int iconWidth, int iconHeight)
{
	setIconSize(BSize(iconWidth, iconHeight));
}
void BButton::setIconSize(const BSize& iconSize)
{
	if (member.iconSize != iconSize)
	{
		member.iconSize = iconSize;
		this->fresh();
	}
}
const BSize& BButton::iconSize() const
{
	return member.iconSize;
}

void BButton::setCheckable(bool checkable)
{
	if (member.checkable != checkable)
	{
		member.checkable = checkable;
		member.checked = false;
		this->fresh();
	}
}
bool BButton::checkable() const
{
	return member.checkable;
}

void BButton::setChecked(bool checked)
{
	if (!member.checkable)
		return;
	if (member.checked != checked)
	{
		member.checked = checked;
		emit(Signal_Checked, checked);
		this->fresh();
	}
}
bool BButton::checked() const
{
	return member.checked;
}

BSize BButton::sizeHint() const
{
	BSize textSize = member.textSize;
	const BFont* font = this->font();
	if (font)
	{
		if (member.t_text.empty())
			textSize = font->textSize(member.text);
		else
			textSize = font->textSize(member.t_text);
	}

	BSize iconSize = member.iconSize;
	if (iconSize.width() < textSize.height())
		iconSize.width() = textSize.height();
	if (iconSize.height() < textSize.height())
		iconSize.height() = textSize.height();

	BSize hsize = iconSize;
	if (!member.icon || !member.iconAlone)
	{
		hsize.width() += textSize.width();
		hsize.height() = bMax(hsize.height(), textSize.height());
	}

	return this->shellSize() + hsize;
}

void BButton::resizeEvent(const BEvent& event)
{
	BRect crect = this->clientRect();
	member.dirty = true;
	this->fresh();
}
void BButton::changeEvent(const BChangeEvent& changeEvent)
{
	switch (changeEvent.change())
	{
	case Change_Able:
		if (changeEvent.able() && member.state == State_Disable)
			member.state = State_Normal;
		if (!changeEvent.able() && member.state != State_Disable)
			member.state = State_Disable;
		this->fresh();
		break;
	case Change_Margin:
	case Change_Perch:
	case Change_Border:
		member.dirty = true;
		this->fresh();
		break;
	}
}

void BButton::styleEvent(const BEvent& event)
{
	const BStyle* style = this->realStyle();
	if (style)
	{
		const BValue& iconSizeValue = style->value(Value_Icon_Size);
		if (iconSizeValue.valid())
			member.iconSize = iconSizeValue;

		const BValue& iconValue = style->value(Value_Icon);
		if (iconValue.valid())
			member.icon = (BIcon*)iconValue;

		const BValue& spaceValue = style->value(Value_Space);
		if (spaceValue.valid())
			member.space = spaceValue;

		const BValue& imageSizeValue = style->value(Value_Image_Size);
		if (imageSizeValue.valid())
			member.imageSize = imageSizeValue;
	}
	else
	{
		member.iconSize = BSize();
		member.icon = 0;
		member.space = 0;
		member.imageSize = BSize();
	}
	member.dirty = true;
	this->adjust();
}
void BButton::freshEvent(const BEvent& event)
{
	if (member.dirty)
	{
		member.freshRects();
		member.dirty = false;
	}
}
void BButton::paintEvent(const BEvent& event)
{
	BRect crect = this->clientRect();

	BPainter painter(this);
	if (!this->able())
	{
		painter.drawBackground(State_Disable);
		painter.drawContent(State_Disable);
	}
	else if (member.checked)
	{
		painter.drawBackground(State_Checked);
		painter.drawContent(State_Checked);
	}
	else
	{
		painter.drawBackground(member.state);
		painter.drawContent(member.state);
	}
	if (member.color.a() > 1)
	{
		painter.setColor(member.color);
		painter.fillRect(crect);
	}
	if(member.image)
	{
		painter.drawImage(member.imageRect, member.image);
	}
	if (member.icon)
	{
		State state = member.state;
		if (!this->able())
			state = State_Disable;
		if (member.checked)
			state = State_Checked;
		BImage* image = member.icon->image(state);
		if (image)
		{
			painter.drawImage(member.iconRect, image);
		}
	}
	bool showText = !(member.icon && member.iconAlone);
	if (showText && member.text.size())
	{
		StyleRole role = Color_Text;
		if (!this->able())
			role = Color_Text_Disable;
		if (member.state == State_Hovered)
			role = Color_Text_Hovered;
		if (member.state == State_Pressed)
			role = Color_Text_Pressed;
		if (member.checked)
			role = Color_Text_Checked;
		painter.setColor(role);
		if (member.t_text.size())
			painter.drawText(member.textRect, member.t_text);
		else
			painter.drawText(member.textRect, member.text);
	}
	painter.drawBorder();
	painter.drawPerch();
	painter.drawMargin();
}

void BButton::mouseEnterEvent(const BMouseEvent& mouseEvent)
{
	if (member.state != State_Hovered)
	{
		member.state = State_Hovered;
		this->fresh();
	}
}
void BButton::mouseLeaveEvent(const BMouseEvent& mouseEvent)
{
	if (member.state != State_Normal)
	{
		member.state = State_Normal;
		this->fresh();
	}
}

void BButton::mousePressEvent(const BMouseEvent& mouseEvent)
{
	if (member.state != State_Pressed)
	{
		member.state = State_Pressed;
		this->fresh();
	}
}
void BButton::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	if (member.state != State_Hovered)
	{
		member.state = State_Hovered;
		this->fresh();
	}
}

void BButton::mouseClickEvent(const BMouseEvent& mouseEvent)
{
	const BPoint& point = mouseEvent.pos();
	if (member.checkable)
	{
		setChecked(!member.checked);
	}
	emit(Signal_Clicked);
}
